﻿namespace TNet
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;

    public class Buffer
    {
        private int mCounter;
        private bool mInPool;
        private static TNet.List<TNet.Buffer> mPool = new TNet.List<TNet.Buffer>();
        private BinaryReader mReader;
        private int mSize;
        private MemoryStream mStream = new MemoryStream();
        private BinaryWriter mWriter;
        private bool mWriting;

        private Buffer()
        {
            this.mWriter = new BinaryWriter(this.mStream);
            this.mReader = new BinaryReader(this.mStream);
        }

        public BinaryWriter BeginPacket(byte packetID)
        {
            BinaryWriter writer = this.BeginWriting(false);
            writer.Write(0);
            writer.Write(packetID);
            return writer;
        }

        public BinaryWriter BeginPacket(Packet packet)
        {
            BinaryWriter writer = this.BeginWriting(false);
            writer.Write(0);
            writer.Write((byte) packet);
            return writer;
        }

        public BinaryWriter BeginPacket(Packet packet, int startOffset)
        {
            BinaryWriter writer = this.BeginWriting(startOffset);
            writer.Write(0);
            writer.Write((byte) packet);
            return writer;
        }

        public BinaryReader BeginReading()
        {
            if (this.mWriting)
            {
                this.mWriting = false;
                this.mSize = (int) this.mStream.Position;
                this.mStream.Seek(0L, SeekOrigin.Begin);
            }
            return this.mReader;
        }

        public BinaryReader BeginReading(int startOffset)
        {
            if (this.mWriting)
            {
                this.mWriting = false;
                this.mSize = (int) this.mStream.Position;
            }
            this.mStream.Seek((long) startOffset, SeekOrigin.Begin);
            return this.mReader;
        }

        public BinaryWriter BeginWriting(bool append)
        {
            if (!append || !this.mWriting)
            {
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mSize = 0;
            }
            this.mWriting = true;
            return this.mWriter;
        }

        public BinaryWriter BeginWriting(int startOffset)
        {
            this.mStream.Seek((long) startOffset, SeekOrigin.Begin);
            this.mWriting = true;
            return this.mWriter;
        }

        public void Clear()
        {
            this.mCounter = 0;
            this.mSize = 0;
            if (this.mStream.Capacity > 0x400)
            {
                this.mStream.SetLength(0x100L);
            }
            this.mStream.Seek(0L, SeekOrigin.Begin);
            this.mWriting = true;
        }

        public void CopyTo(TNet.Buffer target)
        {
            BinaryWriter writer = target.BeginWriting(false);
            int size = this.size;
            if (size > 0)
            {
                writer.Write(this.buffer, this.position, size);
            }
            target.EndWriting();
        }

        public static TNet.Buffer Create()
        {
            return Create(true);
        }

        public static TNet.Buffer Create(bool markAsUsed)
        {
            TNet.Buffer buffer = null;
            if (TNet.Buffer.mPool.size == 0)
            {
                buffer = new TNet.Buffer();
            }
            else
            {
                TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
                lock (mPool)
                {
                    if (TNet.Buffer.mPool.size != 0)
                    {
                        buffer = TNet.Buffer.mPool.Pop();
                        buffer.mInPool = false;
                    }
                    else
                    {
                        buffer = new TNet.Buffer();
                    }
                }
            }
            buffer.mCounter = !markAsUsed ? 0 : 1;
            return buffer;
        }

        public void Dispose()
        {
            this.mStream.Dispose();
        }

        public int EndPacket()
        {
            if (this.mWriting)
            {
                this.mSize = this.position;
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mWriter.Write((int) (this.mSize - 4));
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mWriting = false;
            }
            return this.mSize;
        }

        public int EndTcpPacketStartingAt(int startOffset)
        {
            if (this.mWriting)
            {
                this.mSize = this.position;
                this.mStream.Seek((long) startOffset, SeekOrigin.Begin);
                this.mWriter.Write((int) ((this.mSize - 4) - startOffset));
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mWriting = false;
            }
            return this.mSize;
        }

        public int EndTcpPacketWithOffset(int offset)
        {
            if (this.mWriting)
            {
                this.mSize = this.position;
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mWriter.Write((int) (this.mSize - 4));
                this.mStream.Seek((long) offset, SeekOrigin.Begin);
                this.mWriting = false;
            }
            return this.mSize;
        }

        public int EndWriting()
        {
            if (this.mWriting)
            {
                this.mSize = this.position;
                this.mStream.Seek(0L, SeekOrigin.Begin);
                this.mWriting = false;
            }
            return this.mSize;
        }

        ~Buffer()
        {
            this.mStream.Dispose();
        }

        public bool MarkAsUnused()
        {
            if (Interlocked.Decrement(ref this.mCounter) > 0)
            {
                return false;
            }
            this.mSize = 0;
            this.mStream.Seek(0L, SeekOrigin.Begin);
            this.mWriting = true;
            return true;
        }

        public void MarkAsUsed()
        {
            Interlocked.Increment(ref this.mCounter);
        }

        public int PeekByte(int offset)
        {
            long position = this.mStream.Position;
            if ((offset + 1) > position)
            {
                return -1;
            }
            this.mStream.Seek((long) offset, SeekOrigin.Begin);
            int num2 = this.mReader.ReadByte();
            this.mStream.Seek(position, SeekOrigin.Begin);
            return num2;
        }

        public int PeekInt(int offset)
        {
            long position = this.mStream.Position;
            if ((offset + 4) > position)
            {
                return -1;
            }
            this.mStream.Seek((long) offset, SeekOrigin.Begin);
            int num2 = this.mReader.ReadInt32();
            this.mStream.Seek(position, SeekOrigin.Begin);
            return num2;
        }

        public bool Recycle()
        {
            return this.Recycle(true);
        }

        public bool Recycle(bool checkUsedFlag)
        {
            if (this.mInPool || (checkUsedFlag && !this.MarkAsUnused()))
            {
                return false;
            }
            this.mInPool = true;
            TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
            lock (mPool)
            {
                this.Clear();
                TNet.Buffer.mPool.Add(this);
            }
            return true;
        }

        public static void Recycle(Queue<TNet.Buffer> list)
        {
            TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
            lock (mPool)
            {
                while (list.Count != 0)
                {
                    TNet.Buffer item = list.Dequeue();
                    item.Clear();
                    TNet.Buffer.mPool.Add(item);
                }
            }
        }

        public static void Recycle(Queue<Datagram> list)
        {
            TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
            lock (mPool)
            {
                while (list.Count != 0)
                {
                    TNet.Buffer item = list.Dequeue().buffer;
                    item.Clear();
                    TNet.Buffer.mPool.Add(item);
                }
            }
        }

        public static void Recycle(TNet.List<TNet.Buffer> list)
        {
            TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
            lock (mPool)
            {
                for (int i = 0; i < list.size; i++)
                {
                    TNet.Buffer item = list[i];
                    item.Clear();
                    TNet.Buffer.mPool.Add(item);
                }
                list.Clear();
            }
        }

        public static void Recycle(TNet.List<Datagram> list)
        {
            TNet.List<TNet.Buffer> mPool = TNet.Buffer.mPool;
            lock (mPool)
            {
                for (int i = 0; i < list.size; i++)
                {
                    Datagram datagram = list[i];
                    TNet.Buffer item = datagram.buffer;
                    item.Clear();
                    TNet.Buffer.mPool.Add(item);
                }
                list.Clear();
            }
        }

        public byte[] buffer
        {
            get
            {
                return this.mStream.GetBuffer();
            }
        }

        public int position
        {
            get
            {
                return (int) this.mStream.Position;
            }
            set
            {
                this.mStream.Seek((long) value, SeekOrigin.Begin);
            }
        }

        public static int recycleQueue
        {
            get
            {
                return mPool.size;
            }
        }

        public int size
        {
            get
            {
                return (!this.mWriting ? (this.mSize - ((int) this.mStream.Position)) : ((int) this.mStream.Position));
            }
        }

        public MemoryStream stream
        {
            get
            {
                return this.mStream;
            }
        }
    }
}

